####This is the lllm library (llllm? lllml? llll?).
### It implements a set of commonly used assembly facilities under Linux
### for use with lllm.
### Syscall numbers can be found at `/usr/include/asm/unistd_64.h` !
(def Comment (or true

(defn syscall (code &opt arg1 arg2 arg3 arg4 arg5 arg6) ~[
 ,;(if arg1 ~[[mov rdi ,arg1]] []) # Cannot be a default; must be missing if unspecified!
 ,;(if arg2 ~[[mov rsi ,arg2]] [])
 ,;(if arg3 ~[[mov rdx ,arg3]] [])
 ,;(if arg4 ~[[mov r10 ,arg4]] [])
 ,;(if arg5 ~[[mov r8  ,arg5]] [])
 ,;(if arg6 ~[[mov r9  ,arg6]] [])
 [mov rax ,code]
 [syscall]
 ])
(defn str (s)
  (string "\"" s "\"")) # Simple util to convert something to an assembly string.
(defn str-nl (s)
  (string "\"" s "\"," 10))
#
## Syscalls.
#
(var .data @[])

(defn read (&opt file-descriptor buffer buffer-len)
  (default file-descriptor 0) #Stdin.
  (default buffer-len 1) #Character read. Cannot infer buffer.
  (syscall 0 #Read input,
           buffer #put into that buffer,
           buffer-len )) #of length this.

(defn write (&opt file-descriptor buffer buffer-len)
  (default file-descriptor 1) #Stdout.
  (default buffer 10) #\n.
  (default buffer-len (length buffer))
  (syscall 1 #Write,
           file-descriptor #to that,
           buffer #this,
           buffer-len )) #of length thon.

(defn open (&opt path flags) #->push rax = file-descriptor
  (default flags 0) # O_RDONLY (Read only).
  (syscall 2
           path
           flags))

(defn exit (&opt status-code)
  (default status-code 0) # Default is 0 (success).
  (syscall 60
           status-code))

#
##Useful utils.
#
(defn print-k (literal &opt lngth) # Print a compile-time literal.
 (default lngth (length literal) )
 (def symbol- (symbol "print_k" (gensym)))
  (array/push .data [(symbol symbol- ": db " literal) ])
  (write   #Write,
    1 #to stdout.
    symbol- #that,
    lngth)) # of length (length that).
(defn print-k-nl (literal &opt lngth)
  (default lngth (+ 1 (length literal)) )
  (print-k (str-nl literal) lngth) )

))#<--EndComment.



(def bootload-bytes [85 170] ) #0x55 0xAA
(def bioscall '[int 16]) #int 0x10 , bios call.
(def modes {:teletype 14 :tty 14})
(defn bootload
"Append magic byte operation to a buffer that's under 512 bytes.
(BIOS, not UEFI. Real mode.)
If you want to jump over the buffer, call with symbol jump ."
  (&opt buff<512b jmps?)
  (default buff<512b @[] )
  ~@[ ,;buff<512b
     ,;(if (= jmps? 'jump) ["jmp 513"] [] ) #TODO: check if it's indeed 513?
     ["times 510-($-$$) db 0"] #Pad with zeros until 510th byte.
     [db ,;bootload-bytes]
    ])
(defn mode (kmode)
  ~[mov ah
    ,(cond (keyword? kmode)
           (assert (modes kmode)
                   (string/format "error-unimplemented-bios-mode %j" kmode))
           (number? kmode)
           kmode
           (do (printf "(! mode %j)" kmode)
               kmode)) #Add anyways.
    ])
(defn print-k-char (chr)
  "Return array of instructions to print a single char.
   REMOVE THIS LINE IN PRODUCTION: Tip: extend via mapcat : (mapcat print-k-char \"Hello!\")"
  ~[[mov al
  ,(cond (and (string? chr)
              (= (length chr) 1))
         ((string/bytes chr) 0) #((bytes) 1), single length tuple.
         (number? chr)
         chr
         (do (printf "(! print-k-char %j)" chr)
             chr))]
   ,bioscall] )
